// Core Conf用于控制http协议解析等相关的核心配置.

use std::sync::Arc;

use crate::error::*;
use serde::{Deserialize, Serialize};

// HeaderBuffer最小尺寸.
pub static MIN_HEADER_BUF_SIZE: usize = 1024;
// 可写空间不足 HEADER_BUF_MIN_WRITEABLE_SIZE时, 我们将不再写入.
#[allow(dead_code)]
pub static HEADER_BUF_MIN_WRITEABLE_SIZE: usize = 128;
// MAX_HEADER_SIZE最小限制.
pub static MIN_MAX_HEADER_SIZE: usize = 1024;
// 读取Header的最小超时时间.
pub static MIN_READ_HEADER_TIMEOUT_MS: usize = 10;
// 读取Header的最小超时时间.
pub static MIN_WRITE_HEADER_TIMEOUT_MS: usize = 10;
// BODY BUFFER的最小尺寸
pub static MIN_BODY_BUFFER_SIZE: usize = 4096;
// 当buffer中的空间小于128字节时, 我们不再写入.
#[allow(dead_code)]
pub static BODY_BUFFER_MIN_WRITE_SIZE: usize = 128;
// 每次读取的最小等待时间.
pub static MIN_BODY_READ_TIMEOUT_MS: usize = 5;
// 每次发送最小等待时间.
pub static MIN_BODY_WRITE_TIMEOUT_MS: usize = 5;
// Chunked LINE SIZE
#[allow(dead_code)]
pub static MAX_CHUNKED_LINE_SIZE: usize = 512;

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct HttpCoreConf {
    // 解析http headers时是否忽略invalid header, 默认为true
    pub ignore_invalid_header: Option<bool>,

    // 单个header buf的大小
    // 一个完整的解析行不可超过该配置限定的大小.
    // 默认4K.
    pub one_header_buf_size: Option<usize>,

    // 请求头限定大小.
    // 默认 64K
    pub max_header_size: Option<usize>,

    // 读取client header的最长超时时间
    // 默认30s
    pub server_read_header_timeout_ms: Option<usize>,

    // 服务端发送response header的最长超时时间.
    // 默认30s
    pub server_write_header_timeout_ms: Option<usize>,

    // 向OS发送request header的最长超时时间
    // 默认30s
    pub client_write_header_timeout_ms: Option<usize>,

    // 从OS读取response header的最长时间
    // 默认30s
    pub client_read_header_timeout_ms: Option<usize>,

    // body_buf大小. 默认32K, 不允许小于4K.
    pub body_buf_size: Option<usize>,

    // 每次读取body的等待时间.
    // 默认30s
    pub body_read_timeout_ms: Option<usize>,

    // 每次发送body的等待时间
    // 默认30s
    pub body_write_timeout_ms: Option<usize>,

    // http框架最多丢弃的request body大小.
    // 默认是64K.
    pub max_discard_request_body: Option<usize>,

    // 客户端keepalive最长超时时间.
    // 默认60s.
    pub server_keepalive_timeout_ms: Option<usize>,

    // 服务端收到Expect: 100 continue后, 是否立即回复100-Continue.
    // 默认false.
    pub send_100_continue: Option<bool>,
}

#[allow(dead_code)]
impl HttpCoreConf {
    pub fn to_runtime_conf(
        &self,
        pre_conf: Option<&Arc<HttpCoreRuntimeConf>>,
    ) -> Result<Arc<HttpCoreRuntimeConf>> {
        let def_ignore_invalid_header;
        let def_one_header_buf_size;
        let def_max_header_size;
        let def_server_read_header_timeout_ms;
        let def_server_write_header_timeout_ms;
        let def_client_write_header_timeout_ms;
        let def_client_read_header_timeout_ms;
        let def_body_buf_size;
        let def_body_read_timeout_ms;
        let def_body_write_timeout_ms;
        let def_max_discard_request_body;
        let def_server_keepalive_timeout_ms;
        let def_send_100_continue;

        match pre_conf {
            Some(pre_conf) => {
                def_ignore_invalid_header = pre_conf.ignore_invalid_header;
                def_one_header_buf_size = pre_conf.one_header_buf_size;
                def_max_header_size = pre_conf.max_header_size;
                def_server_read_header_timeout_ms =
                    pre_conf.server_read_header_timeout_ms;
                def_server_write_header_timeout_ms =
                    pre_conf.server_write_header_timeout_ms;
                def_client_write_header_timeout_ms =
                    pre_conf.client_write_header_timeout_ms;
                def_client_read_header_timeout_ms =
                    pre_conf.client_read_header_timeout_ms;
                def_body_buf_size = pre_conf.body_buf_size;
                def_body_read_timeout_ms = pre_conf.body_read_timeout_ms;
                def_body_write_timeout_ms = pre_conf.body_write_timeout_ms;
                def_max_discard_request_body =
                    pre_conf.max_discard_request_body;
                def_server_keepalive_timeout_ms =
                    pre_conf.server_keepalive_timeout_ms;
                def_send_100_continue = pre_conf.send_100_continue;
            }
            None => {
                def_ignore_invalid_header = true;
                def_one_header_buf_size = 4 * 1024;
                def_max_header_size = 64 * 1024;
                def_server_read_header_timeout_ms = 30 * 1000;
                def_server_write_header_timeout_ms = 30 * 1000;
                def_client_write_header_timeout_ms = 30 * 1000;
                def_client_read_header_timeout_ms = 30 * 1000;
                def_body_buf_size = 32 * 1024;
                def_body_read_timeout_ms = 30 * 1000;
                def_body_write_timeout_ms = 30 * 1000;
                def_max_discard_request_body = 64 * 1024;
                def_server_keepalive_timeout_ms = 60 * 1000;
                def_send_100_continue = false;
            }
        }

        let ignore_invalid_header = self
            .ignore_invalid_header
            .unwrap_or(def_ignore_invalid_header);
        let one_header_buf_size =
            self.one_header_buf_size.unwrap_or(def_one_header_buf_size);
        let max_header_size =
            self.max_header_size.unwrap_or(def_max_header_size);
        let server_read_header_timeout_ms = self
            .server_read_header_timeout_ms
            .unwrap_or(def_server_read_header_timeout_ms);
        let server_write_header_timeout_ms = self
            .server_write_header_timeout_ms
            .unwrap_or(def_server_write_header_timeout_ms);
        let client_write_header_timeout_ms = self
            .client_write_header_timeout_ms
            .unwrap_or(def_client_write_header_timeout_ms);
        let client_read_header_timeout_ms = self
            .client_read_header_timeout_ms
            .unwrap_or(def_client_read_header_timeout_ms);
        let body_buf_size = self.body_buf_size.unwrap_or(def_body_buf_size);
        let body_read_timeout_ms = self
            .body_read_timeout_ms
            .unwrap_or(def_body_read_timeout_ms);
        let body_write_timeout_ms = self
            .body_write_timeout_ms
            .unwrap_or(def_body_write_timeout_ms);
        let max_discard_request_body = self
            .max_discard_request_body
            .unwrap_or(def_max_discard_request_body);
        let server_keepalive_timeout_ms = self
            .server_keepalive_timeout_ms
            .unwrap_or(def_server_keepalive_timeout_ms);
        let send_100_continue =
            self.send_100_continue.unwrap_or(def_send_100_continue);

        let runtime_conf = HttpCoreRuntimeConf {
            ignore_invalid_header,
            one_header_buf_size,
            max_header_size,
            server_read_header_timeout_ms,
            server_write_header_timeout_ms,
            client_write_header_timeout_ms,
            client_read_header_timeout_ms,
            body_buf_size,
            body_read_timeout_ms,
            body_write_timeout_ms,
            max_discard_request_body,
            server_keepalive_timeout_ms,
            send_100_continue,
        };

        Ok(Arc::new(runtime_conf.valid()?))
    }
}

#[allow(dead_code)]
pub struct HttpCoreRuntimeConf {
    pub ignore_invalid_header: bool,
    pub one_header_buf_size: usize,
    pub body_buf_size: usize,
    pub max_header_size: usize,
    pub server_read_header_timeout_ms: usize,
    pub server_write_header_timeout_ms: usize,
    pub client_write_header_timeout_ms: usize,
    pub client_read_header_timeout_ms: usize,
    pub body_read_timeout_ms: usize,
    pub body_write_timeout_ms: usize,
    pub max_discard_request_body: usize,
    pub server_keepalive_timeout_ms: usize,
    pub send_100_continue: bool,
}

impl HttpCoreRuntimeConf {
    fn valid(mut self) -> Result<Self> {
        self.one_header_buf_size =
            self.one_header_buf_size.max(MIN_HEADER_BUF_SIZE);
        self.max_header_size = self.max_header_size.max(MIN_MAX_HEADER_SIZE);
        self.server_read_header_timeout_ms = self
            .server_read_header_timeout_ms
            .max(MIN_READ_HEADER_TIMEOUT_MS);
        self.server_write_header_timeout_ms = self
            .server_write_header_timeout_ms
            .max(MIN_WRITE_HEADER_TIMEOUT_MS);
        self.client_write_header_timeout_ms = self
            .client_write_header_timeout_ms
            .max(MIN_WRITE_HEADER_TIMEOUT_MS);
        self.client_read_header_timeout_ms = self
            .client_read_header_timeout_ms
            .max(MIN_READ_HEADER_TIMEOUT_MS);
        self.body_buf_size = self.body_buf_size.max(MIN_BODY_BUFFER_SIZE);
        self.body_read_timeout_ms =
            self.body_read_timeout_ms.max(MIN_BODY_READ_TIMEOUT_MS);
        self.body_write_timeout_ms =
            self.body_write_timeout_ms.max(MIN_BODY_WRITE_TIMEOUT_MS);

        Ok(self)
    }
}
